package edu.yonsei.iwb.smarttv.model;

import com.hp.hpl.jena.graph.Node;
import com.hp.hpl.jena.rdf.model.*;
import com.hp.hpl.jena.vocabulary.OWL;
import com.hp.hpl.jena.vocabulary.RDF;
import com.hp.hpl.jena.vocabulary.RDFS;
import edu.yonsei.iwb.smarttv.model.measure.PropertyWeight;
import edu.yonsei.iwb.smarttv.model.measure.PropertyWeightSet;
import edu.yonsei.iwb.smarttv.model.measure.WeightModel;
import java.util.Vector;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Hashtable;

/**
 * 노드들의 웨이트를 저장하기 위한 배열.
 * 
 * @author Joo
 */
public class MatrixModel {

    private Model model;
    private Vector<MNode> nodes;    
    private Hashtable<Resource, Integer> nodeInfo;
    private MArcSet [][] arcMatrix;
    private Property[][] propertyMap;
//    private PropertyWeight [][] pwMatrix;
    private double[][] weightInfo;


    public MatrixModel() {        
        this.nodes = new Vector<MNode>();
        this.nodeInfo = new Hashtable<Resource, Integer>();
    }

    public Vector<MNode> getNodes() {
        return nodes;
    }

    public Hashtable<Resource, Integer> getNodeInfo() {
        return nodeInfo;
    }
    
    public double[][] getWeightInfo(){
        return this.weightInfo;
    }
    
    
    public MArcSet[][] getArcMatrix(){
        return this.arcMatrix;
    }
    
    private boolean isObjectProperty(Resource property) {
        StmtIterator checkObjectProperty = model.listStatements(property, RDF.type, OWL.ObjectProperty);
        return checkObjectProperty.hasNext();
    }

    private boolean isClass(Resource subject) {
        StmtIterator isClass = model.listStatements(subject, RDF.type, OWL.Class);
        return isClass.hasNext();
    }

    public void initializeGraph(Model model, WeightModel weightModel) {
        this.model = model;
//        model.write(System.out, "N-TRIPLE");
        int idOfNode = 0;
        // 모든 클래스를 가져온다.
        ResIterator classList = model.listSubjectsWithProperty(RDF.type, OWL.Class);
        
        Property isDummy = model.getProperty("http://iweb.yonsei.ac.kr/ontologies/smarttv/isDummy");
        Literal valueTrue = model.createTypedLiteral("true", "http://www.w3.org/2001/XMLSchema#boolean");
        
        while (classList.hasNext()) {
            Resource singleClass = classList.nextResource();
            if (!singleClass.isURIResource()) {
                continue;
            }
            // 가져온 클래스에 id를 순서대로 부여한다.
            StmtIterator sm = model.listStatements(singleClass, isDummy, valueTrue);
            MNode n;
            if(sm.hasNext()) {
                n = new MNode(singleClass, idOfNode, NodeType.CLASS_TYPE, true);
            } else {
                n = new MNode(singleClass, idOfNode, NodeType.CLASS_TYPE, false);  
            }
            nodes.add(n);
            
            // 노드들을 검색할 수 있도록 nodeInfo에 저장한다.
            nodeInfo.put(n.getNode(), n.getId());            
            idOfNode++;
        }
//        MNode literalNode = null;
//        nodes.add(literalNode);
  
        this.initializeWeightInfo();        
                
        Hashtable<Property, PropertyWeightSet> weightTable = weightModel.getPropertyWeightTable();
        
        Enumeration<Property> keys = weightTable.keys();
        while(keys.hasMoreElements()){
            Property p = keys.nextElement();
            PropertyWeightSet pws = weightTable.get(p);
            
            for (int i = 0; i < pws.size(); i++) {
                PropertyWeight pw = pws.get(i);
                
                Resource dr = pw.getDomain();
                Resource rr = pw.getRange();
                int domain_id = nodeInfo.get(dr);               
                int range_id = nodeInfo.get(rr);
                
                System.out.println(dr + " = "+domain_id+"/ "+rr +" = "+range_id);
                MArc arc = new MArc(nodes.get(domain_id), nodes.get(range_id), pw.getProperty(), pw.getWeight(), true);
//                MArc arc = new MArc(pw);
                MArcSet marcset1 = this.arcMatrix[domain_id][range_id];
                marcset1.add(arc);
                
                MArc arc2 = new MArc(nodes.get(domain_id), nodes.get(range_id), pw.getProperty(), pw.getWeight(), false);
                MArcSet marcset2 = this.arcMatrix[range_id][domain_id]; // 양 방향으로 다 넣어주는가?
                marcset2.add(arc2);

                
            }
        }
//        
//        // 아크들은 웨이트 순으로 정열하고 제일 작은 아크를 선택한다.
//         Comparator<MArc> comp = new MatrixModel.ArcWeightComparator();
//         for(int i = 0; i < nodes.size(); i++) {
//            for(int j = 0; j < nodes.size(); j++) {
//                Collections.sort(arcMatrix[i][j], comp);                
//            }
//        }
//         this.setDefaultArc();
    }
    
//    public Resource getMinWeightProperty(Resource subject, Resource object) {
//        int subject_id = nodeInfo.get(subject);
//        int object_id = nodeInfo.get(object);
//        MArcSet mset = this.arcMatrix[subject_id][object_id];   
//        
//        Resource returnValue = mset.firstElement().getPropertyURI();
//        
//        Vector<String> propertyLabels = new Vector<String>();
//        Vector<String> objectLabels = new Vector<String>();
//        
//        StmtIterator stmtit1 = model.listStatements(object, RDFS.label, (RDFNode)null);
//        while(stmtit1.hasNext()) {
//            Statement stmt = stmtit1.nextStatement();
//            objectLabels.add(stmt.getString());
//        }
//        
//        for(int i=0; i<mset.size(); i++) {
//            MArc one = mset.get(i);
//            Resource r = one.getPropertyURI();
//            StmtIterator stmtit2 = model.listStatements(r, RDFS.label, (RDFNode)null);
//            while(stmtit2.hasNext()) {
//                Statement stmt = stmtit2.nextStatement();
//                propertyLabels.add(stmt.getString());
//            }
//            
//            for(int k=0; k<propertyLabels.size(); k++) {
//                for(int j=0; j<objectLabels.size(); j++) {
//                    
//                    String plabel = propertyLabels.get(k);                    
//                    String rlabel = objectLabels.get(j);
//                    System.out.println(plabel);
//                    System.out.println(rlabel);
//                    if(rlabel.length() > plabel.length()){
//                        if(rlabel.contains(plabel)){                            
//                            return r;
//                        }                    
//                    }else{
//                        if(plabel.contains(rlabel)){                            
//                            return r;
//                        }
//                    }
//                }
//            }
//        }
//        
//        return returnValue;
//    }
//    
////    public Resource getMinWeightProperty(Resource subject, Resource object) {
////        int subject_id = nodeInfo.get(subject);
////        int object_id = nodeInfo.get(object);
////        MArcSet mset = this.arcMatrix[subject_id][object_id];        
////        return mset.firstElement().getPropertyURI();
////    }
//    
//    public Property[][] getMinWeightPropertyMap(){
//        
//        return this.propertyMap;
//    }

    private void initializeWeightInfo() {
        this.arcMatrix = new MArcSet[nodes.size()][nodes.size()];        
        this.propertyMap = new Property[nodes.size()][nodes.size()];
        
        for (int i = 0; i < nodes.size(); i++) {
            for(int j = 0; j < nodes.size(); j++) {
//                MArcSet temp = new MArcSet();
                arcMatrix[i][j] = new MArcSet();
            }
        }
                
        
        
        this.weightInfo = new double[nodes.size()][nodes.size()];
        Arrays.fill(weightInfo[nodes.size()-1], 99);
        for (int i = 0; i < nodes.size()-1; i++) {
            Arrays.fill(weightInfo[i], Double.POSITIVE_INFINITY);
        }
        
        // 이 부분 주의 요망,
        //Arrays.fill(weightInfo[nodes.size()-1], 99);        
    }
    
//    private void setDefaultArc() {
//        for(int i = 0; i < nodes.size(); i++) {
//            for(int j = 0 ; j < nodes.size(); j++) {                
//                for(int k = 0; k < arcMatrix[i][j].size(); k++) {
//                    if(k ==0) {
//                        MArc marc = this.arcMatrix[i][j].get(k);
//                        marc.setSelected(true);
//                        this.propertyMap[i][j] = this.arcMatrix[i][j].firstElement().getPropertyURI();
//                        this.weightInfo[i][j] = arcMatrix[i][j].get(k).getWeight();        
////                        System.out.println("-----------------------------------------");
////                        System.out.println(arcMatrix[i][j].get(0).toString());
////                        System.out.println(0 + " th = " + arcMatrix[i][j].get(0).getWeight());   
//                    } else {
//                        MArc marc = this.arcMatrix[i][j].get(k);
//                        marc.setSelected(false);                        
//                    }
//                    
////                    System.out.println("-----------------------------------------");
////                    System.out.println(arcMatrix[i][j].get(k).toString());
////                    System.out.println(k + " th = " + arcMatrix[i][j].get(k).getWeight());   
//                }                
//                
//            }
//        }        
//    }
// 
//    
//    // 아크들의 웨이트를 비교하기 위한 클래스
//    private class ArcWeightComparator implements Comparator<MArc>{
//        @Override
//        public int compare(MArc arc1, MArc arc2) {
//            if (arc1.getWeight() > arc2.getWeight()) {
//                return 1;
//            } else if (arc1.getWeight() < arc2.getWeight()) {
//                return -1;
//            } else {
//                return 0;
//            }
//        }
//    }
}
